iT邦幫忙

2022 iThome 鐵人賽

DAY 24
0
Modern Web

Angular牙起來系列 第 24

# Day24 【牙起來】 訂閱Subscribe、被訂閱者Observable - RxJS

  • 分享至 

  • xImage
  •  

Day24 【牙起來】 訂閱Subscribe、被訂閱者Observable - RxJS

Observable中文直譯為可觀測物件
我比較喜歡稱他為 被訂閱者,簡單又直觀


訂閱與被訂閱

訂閱的世界裡有三個名詞

  • Subscriber 訂閱者: 可以訂閱別人
  • Observable 被訂閱者: 可以被訂閱
  • Subscribe 訂閱: 動詞,訂閱本身的行為

每當被訂閱者完成一部影片,會發出通知,
告訴所有訂閱他的訂閱者,說:「欸欸我出一個新的影片囉,快叫大家來看!」

Subscriber 訂閱者 -> (Subscribe) -> Observable 被訂閱者

中文為: 『訂閱者 訂閱了 被訂閱者』
這整個過程則稱為 訂閱事件


程式裡的被訂閱者

方法一、直接訂閱的形式

依照上一次的範例來看,在store.component.ts

  constructor(private http: HttpClient) {
    let url = 'https://63403667d1fcddf69cb402b7.mockapi.io/api/v1/weapons';
    this.http.get(url).subscribe(result => {
      console.log(result);
    });
  }
  • 藍框內 this.http.get(url) 代表被訂閱者
  • 橘框 .subscribe() 表示訂閱的動作

subscribe() 的裡面則是一個callBack函式,把回來的資料result給印出來

方法二、給個變數直接訂閱

也可以寫成這樣,讓變數getData$成為Observable
最後再subscribe()

export class StoreComponent {

  constructor(private http: HttpClient) {
    let url = 'https://63403667d1fcddf69cb402b7.mockapi.io/api/v1/weapons';

    let getData$ = this.http.get(url);
    getData$.subscribe(
      result => {
        console.log(result);
      }
    )
  }

}

在變數命名慣例上,會對Observable物件尾端加上錢字號 $

後綴$能讓人們意會到這個物件是資料流,而非資料本身

方法三、統一管理的形式

也可以長成這樣子
使用Subscription物件來集中管理所有的 訂閱事件

export class StoreComponent {

  subscription = new Subscription();
  
  constructor(private http: HttpClient) {
    let url = 'https://63403667d1fcddf69cb402b7.mockapi.io/api/v1/weapons';

    let getData$ = this.http.get(url);
    
    this.subscription.add(
      getData$.subscribe(
        result => {
          console.log(result);
        }
      )
    )
  }

}

但這個樣子形式還是有點醜,似乎跟原本一樣,沒有什麼意義
所以我們可以再加上 RxJS.pipe() 方法,把要處理的事情都丟進去

.tap() 就是在pipe()管線中要他執行某些事情 Do Something 的意思

把要做的事情、醜醜的code都包裝起來,對外僅露出短短的一行getData$.subscribe()

export class StoreComponent {

  subscription = new Subscription();

  constructor(private http: HttpClient) {
    let url = 'https://63403667d1fcddf69cb402b7.mockapi.io/api/v1/weapons';

    let getData$ = this.http.get(url).pipe(
      tap(
        result => {
          console.log(result);
        }
      )
    );

    this.subscription.add(getData$.subscribe());

  }

}

或者這樣,
先將資料流subscribe(),再放進Subscription物件中

export class StoreComponent {

  subscription = new Subscription();

  constructor(private http: HttpClient) {
    let url = 'https://63403667d1fcddf69cb402b7.mockapi.io/api/v1/weapons';

    let getData$ = this.http.get(url).pipe(
      tap(
        result => {
          console.log(result);
        }
      )
    ).subscribe();

    this.subscription.add(getData$);

  }

}

為什麼推薦這樣子寫呢?
因為等專案大一點之後,如果用方法一
可能會看到類似如下的程式碼

不小心就做了多次訂閱

  constructor(private http: HttpClient) {
    let url = 'https://63403667d1fcddf69cb402b7.mockapi.io/api/v1/weapons';

    let getData$ = this.http.get(url);

    this.subscription.add(
      getData$.subscribe(
        result => {
          console.log(result);
        }
      )
    )

      ...

    this.subscription.add(
      getData$.subscribe(
        result => {
          console.log(result);
        }
      )
    )

  }

運行結果

而使用Subscription物件

對同一個資料流新增多次訂閱事件,也只會做一次訂閱

this.subscription.add(getData$);
this.subscription.add(getData$);
this.subscription.add(getData$);

運行結果

把訂閱集中、收集起來,不僅能確保只做了一次訂閱
對於後續接手的人來說,也能很明確知道這個元件的程式內
總共對哪些資料流做了訂閱,可以一目瞭然

this.subscription.add(getData1$);
this.subscription.add(getData2$);
this.subscription.add(getData3$);

上一篇
# Day23 【牙起來】 元件執行順序 & 生命週期 - Angular
下一篇
# Day25 【牙起來】 路由設定(Router) - Angular
系列文
Angular牙起來30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言